home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Source Code
/
Pascal
/
Applications
/
NIH Image 1.62b11
/
src
/
Math.p
< prev
next >
Wrap
Text File
|
1996-03-01
|
41KB
|
1,564 lines
unit Math;
interface
uses
Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts,
Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
globals, Utilities, RealUtils, Graphics, Camera, Filters, Lut, fft;
procedure SetPasteMode (item: integer);
procedure DoMouseDownInPasteControl (loc: point);
procedure ShowPasteControl;
procedure DrawPasteControl;
procedure DoArithmetic (MenuItem: integer; constant: extended);
function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
procedure DoPasteMath;
procedure DoImageMath;
function GetInfoPtr (PicN: integer): InfoPtr;
implementation
const
Src1Item = 7;
Src2Item = 8;
OpItem = 9;
procedure DoPasteMath;
const
PixelsPerUpdate = 15000;
var
nrows, ncols, hSrcStart, vSrcStart, hDstStart, vDstStart: integer;
SaveInfo: InfoPtr;
h, v, vDst, PixelCount, offset: integer;
Src, Dst: LineType;
tmp, range, min, max, StartTicks: LongInt;
x, xmax, xmin, xrange, xxscale: extended;
begin
if TooWide then
exit(DoPasteMath);
ShowWatch;
OpPending := false;
WhatToUndo := UndoPaste;
KillRoi;
with info^.RoiRect do begin
ncols := right - left;
nrows := bottom - top;
hDstStart := left;
vDstStart := top;
end;
with ClipBufInfo^.RoiRect do begin
hSrcStart := left;
vSrcStart := top;
end;
if hDstStart < 0 then begin
offset := -hDstStart;
hDstStart := 0;
hSrcStart := hSrcStart + offset;
ncols := ncols - offset;
end;
if vDstStart < 0 then begin
offset := -vDstStart;
vDstStart := 0;
vSrcStart := vSrcStart + offset;
nrows := nrows - offset;
end;
with info^.PicRect do begin
if hDstStart + ncols > right then
ncols := right - hDstStart;
if vDstStart + nrows > bottom then
nrows := bottom - vDstStart;
end;
SaveInfo := info;
vDst := vDstStart;
min := 999999;
max := -999999;
xmin := 999999.0;
xmax := -999999.0;
StartTicks := TickCount;
{First pass to find result range}
if ScaleArithmetic then begin
for v := vSrcStart to vSrcStart + nRows - 1 do begin
Info := ClipBufInfo;
GetLine(hSrcStart, v, nCols, Src);
Info := SaveInfo;
GetLine(hDstStart, vDst, nCols, Dst);
case CurrentOp of
AddOp: begin
for h := 0 to nCols - 1 do begin
tmp := Src[h] + Dst[h];
if tmp > max then
max := tmp;
if tmp < Min then
min := tmp;
end;
end;
SubtractOp: begin
for h := 0 to nCols - 1 do begin
tmp := Dst[h] - Src[h];
if tmp > max then
max := tmp;
if tmp < Min then
min := tmp;
end;
end;
MultiplyOp: begin
for h := 0 to nCols - 1 do begin
tmp := Dst[h];
tmp := tmp * Src[h];
if tmp > max then
max := tmp;
if tmp < min then
min := tmp;
end;
end;
DivideOp: begin
for h := 0 to nCols - 1 do begin
tmp := Src[h];
if tmp = 0 then
tmp := 1;
x := Dst[h] / tmp;
if x > xmax then begin
xmax := x;
end;
if x < xmin then
xmin := x;
end;
end;
end;
vDst := vDst + 1;
end;
vDst := vDstStart;
if CurrentOp = DivideOp then begin
xrange := xmax - xmin;
if xrange <> 0.0 then
xxscale := 256.0 / xrange
else
xxscale := 1;
end
else
range := max - min;
end; {if ScaleArithmetic=true}
PixelCount := 0;
{Second pass to do arithmetic and scaling}
for v := vSrcStart to vSrcStart + nRows - 1 do begin
Info := ClipBufInfo;
GetLine(hSrcStart, v, nCols, Src);
Info := SaveInfo;
GetLine(hDstStart, vDst, nCols, Dst);
case CurrentOp of
AddOp:
if ScaleArithmetic then
for h := 0 to nCols - 1 do begin
tmp := Dst[h] + Src[h] - min;
if range <> 0 then
tmp := tmp * 256 div range
else
tmp := BackgroundIndex;
if tmp > 255 then
dst[h] := 255
else
dst[h] := tmp;
end
else
for h := 0 to nCols - 1 do begin
tmp := Dst[h] + Src[h];
if tmp > 255 then
dst[h] := 255
else
dst[h] := tmp;
end;
SubtractOp:
if ScaleArithmetic then
for h := 0 to nCols - 1 do begin
tmp := Dst[h] - Src[h] - min;
if range <> 0 then
tmp := tmp * 256 div range
else
tmp := BackgroundIndex;
if tmp > 255 then
dst[h] := 255
else
dst[h] := tmp;
end
else
for h := 0 to nCols - 1 do begin
tmp := Dst[h] - Src[h];
if tmp < 0 then
dst[h] := 0
else
dst[h] := tmp;
end;
MultiplyOp:
if ScaleArithmetic then
for h := 0 to nCols - 1 do begin
tmp := Dst[h];
tmp := tmp * Src[h] - min;
if range <> 0 then
tmp := tmp * 256 div range
else
tmp := BackgroundIndex;
if tmp > 255 then
dst[h] := 255
else
dst[h] := tmp;
end
else
for h := 0 to nCols - 1 do begin
tmp := Dst[h];
tmp := tmp * Src[h];
if tmp > 255 then
dst[h] := 255
else
dst[h] := tmp;
end;
DivideOp:
if ScaleArithmetic then
for h := 0 to nCols - 1 do begin
tmp := Src[h];
if tmp = 0 then
tmp := 1;
x := Dst[h] / tmp - xmin;
if xrange <> 0.0 then
tmp := trunc(x * xxscale)
else
tmp := BackgroundIndex;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
dst[h] := tmp;
end
else
for h := 0 to nCols - 1 do begin
tmp := Src[h];
if tmp = 0 then
tmp := 1;
dst[h] := Dst[h] div tmp;
end;
end;
PutLine(hDstStart, vDst, nCols, Dst);
vDst := vDst + 1;
PixelCount := PixelCount + ncols;
if PixelCount > PixelsPerUpdate then begin
UpdateScreen(info^.RoiRect);
if CommandPeriod then begin
UpdateScreen(info^.RoiRect);
beep;
exit(DoPasteMath)
end;
PixelCount := 0;
end;
end;
with info^ do begin
ShowTime(StartTicks, RoiRect, '');
UpdateScreen(RoiRect);
end;
end;
procedure SetPasteMode (item: integer);
var
SavePort: GrafPtr;
BlendColor: rgbColor;
begin
if not macro then begin
SetForegroundColor(BlackIndex);
SetBackGroundColor(WhiteIndex);
end;
case Item of
CopyModeItem:
PasteTransferMode := SrcCopy;
AndItem:
PasteTransferMode := NotSrcBic; {And}
OrItem:
PasteTransferMode := SrcOr;
XorItem:
PasteTransferMode := SrcXor;
ReplaceItem:
PasteTransferMode := Transparent;
BlendItem: begin
GetPort(SavePort);
with BlendColor do begin
red := 32767;
blue := 32767;
green := 32767;
end;
SetPort(GrafPtr(info^.osPort));
OpColor(BlendColor);
SetPort(SavePort);
PasteTransferMode := Blend;
end;
otherwise
end; {case}
end;
function GetTransferModeItem: integer;
begin
case PasteTransferMode of
SrcCopy:
GetTransferModeItem := CopyModeItem;
NotSrcBic:
GetTransferModeItem := AndItem;
SrcOr:
GetTransferModeItem := OrItem;
SrcXor:
GetTransferModeItem := XorItem;
Transparent:
GetTransferModeItem := ReplaceItem;
Blend:
GetTransferModeItem := BlendItem;
end;
end;
procedure DrawPasteControl;
const
bWidth = 64;
bHeight = 14;
vinc = 18;
bhloc = 114;
bvloc = 6;
var
tPort: GrafPtr;
i, hloc, vloc, item: integer;
tType: pcItemType;
tRect, TriangleRect: rect;
ItemStr: str255;
begin
GetPort(tPort);
SetPort(PasteControl);
with PcItem[1] do begin
SetRect(r, 15, 22, 95, 40);
itype := pcPopupMenu;
str := 'Transfer Mode';
end;
with pcItem[2] do begin
SetRect(r, 88, 50, 100, 62);
itype := pcCheckBox;
str := 'Scale Math';
end;
with pcItem[3] do begin
SetRect(r, 88, 65, 100, 77);
itype := pcCheckBox;
str := 'Live Paste';
end;
hloc := bhloc;
vloc := bvloc;
tType := pcButton;
with pcItem[4] do begin
SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
itype := tType;
str := 'Add';
end;
vloc := vloc + vinc;
with pcItem[5] do begin
SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
itype := tType;
str := 'Subtract';
end;
vloc := vloc + vinc;
with pcItem[6] do begin
SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
itype := tType;
str := 'Multiply';
end;
vloc := vloc + vinc;
with pcItem[7] do begin
SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
itype := tType;
str := 'Divide';
end;
TextFont(SystemFont);
TextSize(12);
for i := 1 to npcItems do
with pcItem[i] do
case iType of
pcPopupMenu:
with r do begin
MoveTo(r.left - 10, r.top - 4);
DrawString(str);
DrawDropBox(r);
item := GetTransferModeItem;
GetMenuItemText(TransferModeMenuH, item, ItemStr);
MoveTo(left + 13, bottom - 5);
DrawString(ItemStr);
end;
pcCheckBox:
with r do begin
MoveTo(left - StringWidth(str) - 4, bottom - 2);
DrawString(str);
EraseRect(r);
FrameRect(r);
if ((i = 2) and ScaleArithmetic) or ((i = 3) and LivePasteMode) then begin
MoveTo(left, top);
LineTo(right - 1, bottom - 1);
MoveTo(left, bottom - 1);
LineTo(right - 1, top);
end;
end;
pcButton: begin
FrameRoundRect(r, 6, 6);
with r do
MoveTo(left + ((right - left) - StringWidth(str)) div 2, bottom - 3);
DrawString(str);
end;
end; {case}
SetPort(tPort);
end;
procedure DoMouseDownInPasteControl; {(loc:point)}
var
nItem, i, MenuItem: integer;
tr: rect;
begin
if not (OpPending and (CurrentOp = PasteOp)) then begin
PutError('Paste Control is only available during paste operations.');
exit(DoMouseDownInPasteControl);
end;
SetPort(PasteControl);
GlobalToLocal(loc);
nItem := 0;
for i := 1 to npcItems do
if PtInRect(loc, pcItem[i].r) then
nitem := i;
if nItem > 0 then begin
case pcItem[nItem].itype of
pcPopUpMenu:
with pcItem[1].r do begin
MenuItem := PopUpMenu(TransferModeMenuH, left, top, GetTransferModeItem);
SetPasteMode(MenuItem);
end;
pcCheckBox: begin
tr := pcItem[nItem].r;
InsetRect(tr, 1, 1);
FrameRect(tr);
if nitem = 2 then
ScaleArithmetic := not ScaleArithmetic;
if nitem = 3 then begin
LivePasteMode := not LivePasteMode;
if LivePasteMode then begin
ExternalTrigger := false;
UpdateVideoControl
end;
end;
end;
pcButton: begin
InvertRoundRect(pcItem[nitem].r, 6, 6);
while Button and (nitem > 0) do begin
GetMouse(loc);
if not PtInRect(loc, pcItem[nitem].r) then begin
InvertRoundRect(pcItem[nitem].r, 6, 6);
nItem := 0;
end;
end;
end;
end; {case}
repeat
until not button;
if nItem > 0 then
with pcItem[nitem] do begin
case itype of
pcPopupMenu:
;
pcCheckBox: begin
end;
pcButton: begin
InvertRoundRect(pcItem[nitem].r, 6, 6);
if info^.RoiType = RectRoi then begin
case nitem of
4:
CurrentOp := AddOp;
5:
CurrentOp := SubtractOp;
6:
CurrentOp := MultiplyOp;
7:
CurrentOp := DivideOp;
end;
DoPasteMath;
end; {if}
end; {pcButton}
end; {case}
end; {with}
end; {if nitem>0}
if LivePasteMode and (((WhatsOnClip <> CameraPic) and (WhatsOnClip <> LivePic)) or (FrameGrabber =NoFrameGrabber)) then begin
PutError('"Live Paste" requires that a rectangular selection be first copied from the Camera window to the Clipboard.');
LivePasteMode := false;
end;
if LivePasteMode and (info^.PictureType = FrameGrabberType) then begin
PutError('Live pasting into the Camera window is not supported.');
LivePasteMode := false;
end;
DrawPasteControl;
end;
procedure ShowPasteControl;
var
tPort: GrafPtr;
trect: rect;
wp: ^WindowPtr;
begin
SetRect(trect, PasteControlLeft, PasteControlTop, PasteControlLeft + pcwidth, PasteControlTop + pcheight);
PasteControl := NewWindow(nil, trect, 'Paste Control', true, rDocProc, nil, true, 0);
WindowPeek(PasteControl)^.WindowKind := PasteControlKind;
wp := pointer(GhostWindow);
wp^ := PasteControl;
PasteTransferMode := SrcCopy;
LivePasteMode := false;
end;
function GetRealC (message: str255; default: extended; precision: integer; var Canceled: boolean): extended;
const
NumberID = 3;
CalibrateID = 5;
var
mylog: DialogPtr;
item: integer;
begin
InitCursor;
ParamText(message, '', '', '');
mylog := GetNewDialog(290, nil, pointer(-1));
SetDReal(MyLog, NumberID, default, precision);
SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
SelectdialogItemText(MyLog, NumberID, 0, 32767);
OutlineButton(MyLog, ok, 16);
repeat
ModalDialog(nil, item);
if item = CalibrateID then begin
RealArithmetic := not RealArithmetic;
SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
end;
until (item = ok) or (item = cancel);
if item = ok then begin
GetRealC := GetDReal(MyLog, NumberID);
Canceled := false;
end
else begin
GetRealC := default;
Canceled := true;
end;
DisposeDialog(mylog);
end;
procedure DoArithmetic (MenuItem: integer; constant: extended);
var
table: LookupTable;
i, iConst, pNum, digits: integer;
tmp: LongInt;
LogScale: extended;
Canceled: boolean;
result: str255;
begin
canceled := false;
if info^.fit <> Uncalibrated then
RealArithmetic := true;
if not macro then
case menuItem of
AddItem:
constant := GetRealC('Constant to add:', 25, 0, Canceled);
SubtractItem:
constant := GetRealC('Constant to subtract:', 25, 0, Canceled);
MultiplyItem: begin
constant := GetRealC('Constant to multiply by:', 1.25, 2, Canceled);
if constant < 0.0 then begin
PutError('Constant must be positive.');
exit(DoArithmetic);
end;
end;
DivideItem: begin
constant := GetRealC('Constant to divide by:', 1.25, 2, Canceled);
if constant <= 0.0 then begin
PutError('Constant must be nonzero and positive.');
exit(DoArithmetic);
end;
end;
AndItem2:
constant := GetInt('AND image with:', 240, Canceled);
OrItem2:
constant := GetInt('OR image with:', 31, Canceled);
XorItem2:
constant := GetInt('XOR image with:', 31, Canceled);
LogItem: begin
if not CheckCalibration then
exit(DoArithmetic);
constant := 0.0;
LogScale := 255.0 / ln(255.0);
end;
end; {case}
if Canceled then
exit(DoArithmetic);
if RealArithmetic and (MenuItem >= AddItem) and (MenuItem <= DivideItem) and not macro then begin
if constant < 1.0 then
digits := 3
else if constant <10.0 then
digits := 2
else digits := 1;
if trunc(constant) = constant then
digits := 0;
with info^ do case MenuItem of
AddItem: begin
MathGain := 1.0;
MathOffset := constant;
result := StringOf(title, '+', constant:1:digits)
end;
SubtractItem: begin
MathGain := 1.0;
MathOffset := -constant;
result := StringOf(title, '-', constant:1:digits)
end;
MultiplyItem: begin
MathGain := constant;
MathOffset := 0.0;
result := StringOf(title, '*', constant:1:digits)
end;
DivideItem: begin
MathGain := 1.0 / constant;
MathOffset := 0.0;
result := StringOf(title, '/', constant:1:digits)
end;
end;
pNum := info^.picNum;
with info^.PicRect do
if not NewRealWindow(result, right-left, bottom-top) then
exit(DoArithmetic);
CurrentMathOp := CopyMath;
RealImageMath := true;
DoMath(pNum, pNum, Info, info^.picRect);
exit(DoArithmetic);
end;
iconst := trunc(constant);
for i := 0 to 255 do begin
case MenuItem of
AddItem:
tmp := round(i + constant);
SubtractItem:
tmp := round(i - constant);
MultiplyItem:
tmp := round(i * constant);
DivideItem:
tmp := round(i / constant);
AndItem2:
tmp := band(i, iconst);
OrItem2:
tmp := bor(i, iconst);
XorItem2:
tmp := bxor(i, iconst);
LogItem:
if i = 0 then
tmp := 0
else
tmp := round(ln(i) * LogScale);
end;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
table[i] := tmp;
end;
ApplyTable(table);
if (MenuItem >= AddItem) and (MenuItem <= DivideItem) then
RemoveDensityCalibration;
end;
function GetInfoPtr (PicN: integer): InfoPtr;
{Converts a pic number or pid number to an Info ptr.}
var
i: integer;
begin
i := 0;
while (PicN < 0) and (i < nPics) do begin
i := i + 1;
if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
PicN := i;
end;
if (PicN >= 1) and (PicN <= nPics) then
GetInfoPtr := pointer(WindowPeek(PicWindow[PicN])^.RefCon)
else
GetInfoPtr := nil;
end;
procedure ShowRoi(roi:rect);
begin
with roi do ShowMessage(StringOf(left:4, top:4, right-left:4, bottom-top:4));
wait(200);
end;
function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
var
Src1Info, Src2Info: InfoPtr;
ignore:boolean;
begin
KillRoi;
GetMathRoi:=false;
Src1Info := GetInfoPtr(Src1PicNum);
Src2Info := GetInfoPtr(Src2PicNum);
if (Src1Info = nil) or (Src2Info = nil) then begin
PutError('Bad pic num or pid num.');
AbortMacro;
exit(GetMathRoi);
end;
roi := Src1Info^.PicRect;
ignore := SectRect(roi, Src2Info^.PicRect, roi);
GetMathRoi:=true;
end;
procedure DoFFTMath (Src1Info, Src2Info, DstInfo:InfoPtr);
{Does image math when both source images are FFTs.}
var
i, StartTicks: LongInt;
r, c, modAdd, rowMod, colMod, maxN: LongInt;
H2e, H2o, mag: real;
h1, h2, Out: rImagePtr;
roi:rect;
begin
maxN := Src1Info^.pixelsPerLine;
h1 := rImagePtr(Src1Info^.DataH^);
h2 := rImagePtr(Src2Info^.DataH^);
out := rImagePtr(DstInfo^.DataH^);
StartTicks := TickCount;
case CurrentMathOp of
MulMath, cMulMath: {Point by point Hartley multiplication or conjugate multiplication}
for r := 0 to maxN - 1 do begin
rowMod := (maxN - r) mod maxN;
for c := 0 to maxN - 1 do begin
colMod := (maxN - c) mod maxN;
H2e := (h2^[r * maxN + c] + h2^[rowMod * maxN + colMod]) / 2;
H2o := (h2^[r * maxN + c] - h2^[rowMod * maxN + colMod]) / 2;
if CurrentMathOp = cMulMath then
Out^[r * maxN + c] := h1^[r * maxN + c] * H2e - h1^[rowMod * maxN + colMod] * H2o
else
Out^[r * maxN + c] := h1^[r * maxN + c] * H2e + h1^[rowMod * maxN + colMod] * H2o;
end;
end; {for}
DivMath: {Point by point Hartley division}
for r := 0 to maxN - 1 do begin
rowMod := (maxN - r) mod maxN;
for c := 0 to maxN - 1 do begin
colMod := (maxN - c) mod maxN;
mag := H2^[r * maxN + c] * H2^[r * maxN + c] + H2^[rowMod * maxN + colMod] * H2^[rowMod * maxN + colMod];
if mag < 1e-20 then
mag := 1e-20;
H2e := (H2^[r * maxN + c] + H2^[rowMod * maxN + colMod]);
H2o := (H2^[r * maxN + c] - H2^[rowMod * maxN + colMod]);
Out^[r * maxN + c] := (H1^[r * maxN + c] * H2e - H1^[rowMod * maxN + colMod] * H2o) / mag;
end;
end; {for}
end; {case}
info := dstInfo;
DisplayPowerSpectrum(out);
SetFFTWindowName(false);
hunlock(src1Info^.dataH);
hunlock(src2Info^.dataH);
hunlock(dstInfo^.dataH);
SetRect(roi, 0, 0, maxN, maxN);
ShowTime(StartTicks, roi, '');
end; {DoFFTMath}
procedure DoRealRealMath (Src1Info, Src2Info, DstInfo:InfoPtr; roi:rect);
{Does image math when both source images are real.}
var
nrows, ncols, hStart, vStart: LongInt;
h, v, i: LongInt;
tmp, tmp1, tmp2, StartTicks: LongInt;
SaveRow:LongInt;
NextUpdate: LongInt;
MaskRect:rect;
min, max, x, scale, x1, x2: extended;
s1Data, s2Data, rData: rImagePtr;
base: LongInt;
isFFT: boolean;
saveInfo: InfoPtr;
begin
with src1Info^ do begin
if DataH = nil then begin
saveInfo := info;
info := src1Info;
if not ConvertToReal then begin
info := saveInfo;
exit(DoRealRealMath)
end;
end;
hlock(DataH);
s1Data := rImagePtr(DataH^);
isFFT := pos('FFT', title) = 1;
end;
if (CurrentMathOp <> CopyMath) then
with src2Info^ do begin
if DataH = nil then begin
saveInfo := info;
info := src2Info;
if not ConvertToReal then begin
info := saveInfo;
hunlock(DataH);
exit(DoRealRealMath)
end;
end;
hlock(DataH);
s2Data := rImagePtr(DataH^);
isFFT := isFFT and (pos('FFT', title) = 1);
end;
with DstInfo^ do begin
hlock(DataH);
rData := rImagePtr(DataH^);
isFFT := isFFT and (pixelsPerLine = nlines) and isPowerOf2(pixelsPerLine);
end;
if isFFT and (src1Info^.PixelsPerLine = src2Info^.PixelsPerLine)
and (src1Info^.PixelsPerLine = src1Info^.nLines)
and (CurrentMathOp in [MulMath, cMulMath, DivMath]) then begin
doFFTMath(Src1Info, Src2Info, DstInfo);
exit(DoRealRealMath);
end;
with roi do begin
ncols := right - left;
nrows := bottom - top;
hStart := left;
vStart := top;
end;
StartTicks := TickCount;
NextUpdate:=TickCount+10;
min:=10e99;
max:=-10e99;
for v := vStart to vStart + nRows - 1 do begin
base := v * ncols;
case CurrentMathOp of
AddMath:
for h := 0 to nCols - 1 do begin
x := s1Data^[base + h] + s2Data^[base + h];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
SubMath:
for h := 0 to nCols - 1 do begin
x := s1Data^[base + h] - s2Data^[base + h];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MulMath, cMulMath:
for h := 0 to nCols - 1 do begin
x := s1Data^[base + h] * s2Data^[base + h];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
DivMath:
for h := 0 to nCols - 1 do begin
x := s1Data^[base + h] / s2Data^[base + h];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MaxMath:
for h := 0 to nCols - 1 do begin
x1 := s1Data^[base + h];
x2 := s2Data^[base + h];
if x1 >= x2 then
x := x1
else
x := x2;
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MinMath:
for h := 0 to nCols - 1 do begin
x1 := s1Data^[base + h];
x2 := s2Data^[base + h];
if x1 <= x2 then
x := x1
else
x := x2;
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
CopyMath:
for h := 0 to nCols - 1 do begin
x := s1Data^[base + h];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
end; {case}
if TickCount >= NextUpdate then begin
ShowAnimatedWatch;
NextUpdate:=TickCount+10;
if CommandPeriod then begin
beep;
AbortMacro;
exit(DoRealRealMath)
end;
end;
end; {for}
info := dstInfo;
if isFFT then begin
DisplayPowerSpectrum(rData);
SetFFTWindowName(false);
end else
DisplayRealImage(rData, min, max, false);
hunlock(src1Info^.dataH);
if CurrentMathOp <> copyMath then
hunlock(src2Info^.dataH);
hunlock(dstInfo^.dataH);
ShowTime(StartTicks, roi, '');
end; {DoRealRealMath}
procedure DoRealMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
var
nrows, ncols, hStart, vStart: LongInt;
Src1Info, Src2Info: InfoPtr;
h, v, i: LongInt;
src1, src2, dst: LineType;
tmp, tmp1, tmp2, StartTicks: LongInt;
SaveRow:LongInt;
NextUpdate: LongInt;
MaskRect:rect;
min, max, x, scale, x1, x2: extended;
BlackIsZero:boolean;
cvalue1, cvalue2: array[0..255] of extended;
rData: rImagePtr;
base: LongInt;
begin
Src1Info := GetInfoPtr(Src1PicNum);
Src2Info := GetInfoPtr(Src2PicNum);
ShowWatch;
if DstInfo^.DataH = nil then begin
PutError('Output image must be real.');
exit(DoRealMath);
end;
if (src1Info^.dataH <> nil) or (src2Info^.dataH <> nil) then begin
doRealRealMath(Src1Info, Src2Info, DstInfo, roi);
exit(DoRealMath);
end;
with DstInfo^ do begin
if DataH = nil then
exit(DoRealMath);
hlock(DataH);
rData := rImagePtr(DataH^);
end;
BlackIsZero:=((Src1Info^.fit=StraightLine) and (Src1Info^.coefficient[2]<0))
or ((Src2Info^.fit=StraightLine) and (Src2Info^.coefficient[2]<0));
with roi do begin
ncols := right - left;
nrows := bottom - top;
hStart := left;
vStart := top;
end;
info := Src2Info;
GenerateValues;
for i:=0 to 255 do cvalue2[i]:=cvalue[i];
info := Src1Info;
GenerateValues;
for i:=0 to 255 do cvalue1[i]:=cvalue[i];
StartTicks := TickCount;
NextUpdate:=TickCount+10;
min:=10e99;
max:=-10e99;
for v := vStart to vStart + nRows - 1 do begin
info := Src1Info;
GetLine(hStart, v, nCols, src1);
Info := Src2Info;
GetLine(hStart, v, nCols, src2);
base := v * ncols;
case CurrentMathOp of
AddMath:
for h := 0 to nCols - 1 do begin
x := cvalue1[src1[h]] + cvalue2[src2[h]];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
SubMath:
for h := 0 to nCols - 1 do begin
x := cvalue1[src1[h]] - cvalue2[src2[h]];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MulMath, cMulMath:
for h := 0 to nCols - 1 do begin
x := cvalue1[src1[h]] * cvalue2[src2[h]];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
DivMath:
for h := 0 to nCols - 1 do begin
x := cvalue1[src1[h]] / cvalue2[src2[h]];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MaxMath:
for h := 0 to nCols - 1 do begin
x1 := cvalue1[src1[h]];
x2 := cvalue2[src2[h]];
if x1 >= x2 then
x := x1
else
x := x2;
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
MinMath:
for h := 0 to nCols - 1 do begin
x1 := cvalue1[src1[h]];
x2 := cvalue2[src2[h]];
if x1 <= x2 then
x := x1
else
x := x2;
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
CopyMath:
for h := 0 to nCols - 1 do begin
x := cvalue1[src1[h]];
x := x * MathGain + MathOffset;
rData^[base + h] := x;
if x < min then
min := x;
if x > max then
max := x;
end;
end; {case}
if TickCount >= NextUpdate then begin
ShowAnimatedWatch;
NextUpdate:=TickCount+10;
if CommandPeriod then begin
beep;
AbortMacro;
exit(DoRealMath)
end;
end;
end; {for}
info := dstInfo;
DisplayRealImage(rData, min, max, BlackisZero);
hunlock(dstInfo^.dataH);
ShowTime(StartTicks, roi, '');
end; {DoRealMath}
procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
var
nrows, ncols, hStart, vStart: integer;
Src1Info, Src2Info: InfoPtr;
h, v: integer;
src1, src2, dst: LineType;
tmp, tmp1, tmp2, StartTicks, scale, ScaledGain: LongInt;
rtmp,rtmp2: extended;
DoScaling: boolean;
SaveRow:integer;
NextUpdate: LongInt;
MaskRect:rect;
IntegerOffset: LongInt;
begin
if TooWide then
exit(DoMath);
if RealImageMath and not (CurrentMathOp in [AndMath, OrMath, XorMath]) then begin
DoRealMath(Src1PicNum, Src2PicNum, DstInfo, roi);
exit(DoMath);
end;
Src1Info := GetInfoPtr(Src1PicNum);
Src2Info := GetInfoPtr(Src2PicNum);
ShowWatch;
with roi do begin
ncols := right - left;
nrows := bottom - top;
hStart := left;
vStart := top;
end;
StartTicks := TickCount;
scale := 10000;
ScaledGain := round(MathGain * scale);
IntegerOffset := round(MathOffset);
DoScaling := (MathGain <> 1.0) or (MathOffset <> 0.0);
SaveRow:=vStart;
NextUpdate:=TickCount+6; {Update screen 10 times per second}
for v := vStart to vStart + nRows - 1 do begin
info := Src1Info;
GetLine(hStart, v, nCols, src1);
Info := Src2Info;
GetLine(hStart, v, nCols, src2);
case CurrentMathOp of
AddMath:
for h := 0 to nCols - 1 do begin
tmp := src1[h] + src2[h];
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
dst[h] := tmp;
end;
SubMath:
for h := 0 to nCols - 1 do begin
tmp := src1[h] - src2[h];
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
dst[h] := tmp;
end;
MulMath, cMulMath:
for h := 0 to nCols - 1 do begin
tmp := src1[h];
tmp := tmp * src2[h];
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
dst[h] := tmp;
end;
DivMath:
for h := 0 to nCols - 1 do begin
rtmp2:=src2[h];
rtmp := src1[h] / rtmp2;
tmp := round(rtmp * MathGain) + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
dst[h] := tmp;
end;
AndMath:
for h := 0 to nCols - 1 do begin
tmp := band(src1[h], src2[h]);
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
OrMath:
for h := 0 to nCols - 1 do begin
tmp := bor(src1[h], src2[h]);
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
XorMath:
for h := 0 to nCols - 1 do begin
tmp := bxor(src1[h], src2[h]);
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
MaxMath:
for h := 0 to nCols - 1 do begin
tmp1 := src1[h];
tmp2 := src2[h];
if tmp1 >= tmp2 then
tmp := tmp1
else
tmp := tmp2;
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
MinMath:
for h := 0 to nCols - 1 do begin
tmp1 := src1[h];
tmp2 := src2[h];
if tmp1 <= tmp2 then
tmp := tmp1
else
tmp := tmp2;
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
CopyMath:
for h := 0 to nCols - 1 do begin
tmp := src1[h];
if DoScaling then begin
tmp := (tmp * ScaledGain) div scale + IntegerOffset;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end;
dst[h] := tmp;
end;
end;
Info := DstInfo;
PutLine(0, v - vstart, nCols, Dst);
if TickCount>=NextUpdate then begin
SetRect(MaskRect, hStart, SaveRow, hStart+ncols, v + 1);
UpdateScreen(MaskRect);
SaveRow:=v+1;
NextUpdate:=TickCount+6;
ShowAnimatedWatch;
if CommandPeriod then begin
UpdateScreen(info^.RoiRect);
beep;
AbortMacro;
exit(DoMath)
end;
end;
end;
with info^ do begin
ShowTime(StartTicks, RoiRect, '');
SetRect(MaskRect, hStart, SaveRow, hStart+ncols, vStart+nRows);
UpdateScreen(MaskRect);
Changes := true;
RemoveDensityCalibration;
end;
end; {DoMath}
function ImageTitle (var PicNumber: integer): str255;
var
TempInfo: InfoPtr;
begin
if (PicNumber < 1) or (PicNumber > nPics) then
PicNumber := 1;
TempInfo := pointer(WindowPeek(PicWindow[PicNumber])^.RefCon);
ImageTitle := TempInfo^.title;
end;
procedure ImageMathUProc (d: DialogPtr; item: integer);
{User proc for Image Math dialog box}
const
ops = '';
var
str: str255;
VersInfo: str255;
r: rect;
begin
SetPort(d);
GetDItemRect(d, item, r);
DrawDropBox(r);
case item of
Src1Item:
DrawPopUpText(ImageTitle(MathSrc1), r);
Src2Item:
DrawPopUpText(ImageTitle(MathSrc2), r);
OpItem: begin
GetMenuItemText(ImageMathOpsMenuH, ord(CurrentMathOp) + 1, str);
DrawPopUpText(str, r);
end;
end;
end;
function PopUpImageList (r: rect; CurrentImage: integer): integer;
var
i: integer;
begin
for i := 1 to nPics do begin
AppendMenu(ImageListMenuH, ' ');
SetMenuItemText(ImageListMenuH, i, ImageTitle(i));
end;
PopUpImageList := PopUpMenu(ImageListMenuH, r.left, r.top, CurrentImage);
for i := 1 to nPics do
DeleteMenuItem(ImageListMenuH, 1);
end;
procedure DoImageMath;
const
ScaleItem = 10;
OffSetMenuItemText = 11;
ResultItem = 12;
RealMathItem=14;
var
d: DialogPtr;
item, i, MenuItem: integer;
r: rect;
str: str255;
ScaleOffEdited: boolean;
roi:rect;
DstInfo:InfoPtr;
procedure ShowScaleAndOffset;
begin
SetDReal(d, ScaleItem, MathGain, 4);
if RealImageMath then
SetDReal(d, OffSetMenuItemText, MathOffset, 2)
else
SetDNum(d, OffSetMenuItemText, round(MathOffset));
end;
procedure ResetScaleOff;
begin
if not ScaleOffEdited then begin
MathGain := 1.0;
MathOffset := 0.0;
ShowScaleAndOffset;
end;
end;
procedure CheckForRealImage(picNum: integer);
var
srcInfo:InfoPtr;
begin
srcInfo := GetInfoPtr(picNum);
if srcInfo^.dataH <> nil then begin
RealImageMath := true;
SetDlogItem(d, RealMathItem, ord(RealImageMath));
end;
end;
begin
if ImageMathUserProc=nil
then ImageMathUserProc:=NewRoutineDescriptor(@ImageMathUProc, uppUserItemProcInfo, GetCurrentISA);
InitCursor;
ScaleOffEdited := false;
d := GetNewDialog(200, nil, pointer(-1));
SetUProc(d, Src1Item, handle(ImageMathUserProc));
SetUProc(d, Src2Item, handle(ImageMathUserProc));
SetUProc(d, OpItem, handle(ImageMathUserProc));
ShowScaleAndOffset;
SetDString(d, ResultItem, MathResult);
SetDlogItem(d, RealMathItem, ord(RealImageMath));
if (MathSrc1 = 1) and (MathSrc2 = 1) then
MathSrc1 := info^.PicNum;
if MathSrc1 = MathSrc2 then begin
if MathSrc1 = info^.PicNum then begin
MathSrc2 := MathSrc2 + 1;
if MathSrc2 > nPics then
MathSrc2 := 1;
end
else
MathSrc2 := info^.PicNum;
end;
CheckForRealImage(MathSrc1);
CheckForRealImage(MathSrc2);
repeat
ModalDialog(nil, item);
if item = Src1Item then begin
setport(d);
GetDItemRect(d, item, r);
MenuItem := PopUpImageList(r, MathSrc1);
if MenuItem <> 0 then
MathSrc1 := MenuItem;
CheckForRealImage(MathSrc1);
InvalRect(r);
end;
if item = Src2Item then begin
setport(d);
GetDItemRect(d, item, r);
MenuItem := PopUpImageList(r, MathSrc2);
if MenuItem <> 0 then
MathSrc2 := MenuItem;
CheckForRealImage(MathSrc2);
InvalRect(r);
end;
if item = OpItem then begin
setport(d);
GetDItemRect(d, item, r);
MenuItem := PopUpMenu(ImageMathOpsMenuH, r.left, r.top, ord(CurrentMathOp) + 1);
case MenuItem of
1: begin
CurrentMathOp := AddMath;
if not ScaleOffEdited then begin
if RealImageMath then
ResetScaleOff
else begin
MathGain := 0.5;
MathOffset := 0.0;
ShowScaleAndOffset;
end;
end;
end;
2: begin
CurrentMathOp := SubMath;
if not ScaleOffEdited then begin
if RealImageMath then
ResetScaleOff
else begin
MathGain := MathSubGain;
MathOffset := MathSubOffset;
ShowScaleAndOffset;
end;
end;
end;
3: begin
CurrentMathOp := MulMath;
if not ScaleOffEdited then begin
if RealImageMath then
ResetScaleOff
else begin
MathGain := 1.0 / 255.0;
MathOffset := 0.0;
ShowScaleAndOffset;
end;
end;
end;
4: begin
CurrentMathOp := DivMath;
if not ScaleOffEdited then begin
if RealImageMath then
ResetScaleOff
else begin
MathGain := 255.0;
MathOffset := 0.0;
ShowScaleAndOffset;
end;
end;
end;
5: begin
CurrentMathOp := AndMath;
ResetScaleOff;
end;
6: begin
CurrentMathOp := OrMath;
ResetScaleOff;
end;
7: begin
CurrentMathOp := XorMath;
ResetScaleOff;
end;
8: begin
CurrentMathOp := MaxMath;
ResetScaleOff;
end;
9: begin
CurrentMathOp := MinMath;
ResetScaleOff;
end;
10: begin
CurrentMathOp := cMulMath;
ResetScaleOff;
end;
11: begin
CurrentMathOp := CopyMath;
ResetScaleOff;
end;
otherwise
end;
InvalRect(r);
end;
if item = ScaleItem then begin
MathGain := GetDReal(d, ScaleItem);
ScaleOffEdited := true;
end;
if item = OffSetMenuItemText then begin
MathOffset := GetDReal(d, OffSetMenuItemText);
ScaleOffEdited := true;
end;
if item = RealMathItem then begin
RealImageMath := not RealImageMath;
SetDlogItem(d, RealMathItem, ord(RealImageMath));
ResetScaleOff;
end;
until (item = ok) or (item = cancel);
MathResult := GetDString(d, ResultItem);
DisposeDialog(d);
if item = cancel then
exit(DoImageMath);
if not GetMathRoi(MathSrc1, MathSrc2, roi) then
exit(DoImageMath);
with roi do
if RealImageMath then begin
if not NewRealWindow(MathResult, right-left, bottom-top) then
exit(DoImageMath)
end else begin
if not NewPicWindow(MathResult, right-left, bottom-top) then
exit(DoImageMath)
end;
DstInfo := Info;
DoMath(MathSrc1, MathSrc2, DstInfo, roi);
if CurrentMathOp=SubMath then begin
MathSubGain:=MathGain;
MathSubOffset:=MathOffset;
end;
end;
end.